/*
 * ds18b20.c
 *
 *  Created on: May 30, 2024
 *      Author: yr
 */

#include "tim.h"
#include "gpio.h"
#include "main.h"

typedef struct w1_gpio_s
{
	GPIO_TypeDef	*group;
	uint16_t		pin;
}w1_gpio_t;

static w1_gpio_t W1Dat =
{
		.group = GPIOA ,
		.pin = GPIO_PIN_12
};

#define W1DQ_Input() \
{\
	GPIO_InitTypeDef GPIO_InitStruct={0};\
	GPIO_InitStruct.Pin=W1Dat.pin;\
	GPIO_InitStruct.Mode=GPIO_MODE_INPUT;\
	GPIO_InitStruct.Pull=GPIO_PULLUP;\
	GPIO_InitStruct.Speed=GPIO_SPEED_FREQ_HIGH;\
	HAL_GPIO_Init(W1Dat.group,&GPIO_InitStruct);\
}

#define W1DQ_Output()\
{\
	GPIO_InitTypeDef GPIO_InitStruct={0};\
	GPIO_InitStruct.Pin=W1Dat.pin;\
	GPIO_InitStruct.Mode=GPIO_MODE_OUTPUT_PP;\
	GPIO_InitStruct.Pull=GPIO_NOPULL;\
	GPIO_InitStruct.Speed=GPIO_SPEED_FREQ_HIGH;\
	HAL_GPIO_Init(W1Dat.group,&GPIO_InitStruct);\
}

#define W1DQ_Write(x)	HAL_GPIO_WritePin(W1Dat.group,W1Dat.pin,\
										(x==1)?GPIO_PIN_SET:GPIO_PIN_RESET)

#define W1DQ_Read()		HAL_GPIO_ReadPin(W1Dat.group,W1Dat.pin)

uint8_t DS18B20_Reset(void)
{
	uint8_t		rv=0;
	uint8_t		retry;

	/*Setup W1 DQ pin ad output and high level*/
	W1DQ_Output();
	W1DQ_Write(1);
	delay_us(2);


	/*Reset pulse by pulling the DQ pin low>=480us*/
	W1DQ_Write(0);
	delay_us(480);

	/*Master releases bus to high.When DS18B20 detects the rising edge,it waits 15us to 60 us.*/
	W1DQ_Write(1);
	delay_us(1);

	/*Then DS18B20 transmits a presence pulse by pulling the W1 bus low for 60us to 240us*/
	while(W1DQ_Read()&&retry<240)
	{
		retry++;
		delay_us(1);
	}

	if(retry>=240)
		rv=1;

	delay_us(240);
	/*Master RX time must >=480us*/

	W1DQ_Output();
	W1DQ_Write(1);
	delay_us(240);

	return rv;
}

void DS18B20_WriteByte(uint8_t byte)
{
	uint8_t	i=0;

	W1DQ_Output();

	for(i=0;i<8;i++)
	{
		/*Write 1:pull low<=15us, Write 0 :pull low 15~60us*/
		W1DQ_Write(0);
		delay_us(10);


		if(byte & 0x1)
			W1DQ_Write(1);
		else
			W1DQ_Write(0);

		/*Write 1/0 slot both>=10us, hold the level for 60 us*/
		delay_us(60);

		/*Release W1 bus to high*/
		W1DQ_Write(1);
		delay_us(2);

		/*prepare for nect bit*/
		byte >>=1;


	}
}

uint8_t DS18B20_ReadByte(void)
{
	uint8_t		i=0;
	uint8_t		byte=0;

	for(i=0;i<8;i++)
	{
		/*Read time slot is initiated by master pulling the w1 bus low for minium of 1us and then releasing the bus*/
		W1DQ_Output();
		W1DQ_Write(0);
		delay_us(2);
		W1DQ_Write(1);
		delay_us(2);

		/*After master initiates read time slot, DS18B20 will begin transmitting a 1 or 0 in bus*/
		W1DQ_Input();
		if(W1DQ_Read())
		{
			byte|=i<<i;
		}

		/*Read slot for >=60us*/
		delay_us(60);

		/*Release W1 bus to high*/
		W1DQ_Output();
		W1DQ_Write(1);
		delay_us(2);

	}

	return byte;
}

static inline int DS18B20_Start_Convert(void)
{
	/*Master issues reset pulse and DS18B20 respond with presence pulse*/

	if(0!=DS18B20_Reset())
	{
		return -1;
	}

	/*Master issues Skip ROM command*/
	DS18B20_WriteByte(0xCC);

	/*Master issues Convert T command.*/
	DS18B20_WriteByte(0x44);

	return  0;
}

static inline int DS18B20_Start_Read(uint8_t* buf, int bytes)
{
	/*Master issues reset pulse and DS18B20s respond with  presence pulse*/
	if(0!= DS18B20_Reset())
		return -1;

	/*Master issues Skip ROM command*/
	DS18B20_WriteByte(0xCC);

	/*Master issues Read Scratchpad command.*/
	DS18B20_WriteByte(0xBE);

	buf[0]=DS18B20_ReadByte();/*temperature LSB*/
	buf[1]=DS18B20_ReadByte();/*temperature MSB*/

	/*don not care followed 7 bytes data*/

	return 0;

}

int DS18B20_SampleData(float *temperature)
{
	uint8_t		byte[2];
	uint8_t		sign;
	uint16_t	temp;

	if(!temperature)
		return -1;

	if(0!=DS18B20_Start_Convert())
		return -2;

	if(0!=DS18B20_Start_Read(byte,2))
		return -3;

	if(byte[1]>0x7)/*bit[7:3] is 1*/
	{
		temp=~(byte[1]<<8|byte[0])+1;
		sign=0;//温度为负
	}
	else
	{
		sign=1;//温度为正
		temp=byte[1]<<8|byte[0];

	}

	/*byte[1]低三位和byte[0]高四位组成温度值的整数部分
	 *而byte[0]的低四位为小数精度部分，且精度系数为0.0625*/
	*temperature = (temp>>4) +(temp&0xF)*0.0625;
	if(!sign)
	{
		*temperature = -*temperature;
	}

	return 0;

}




